#include "Minute.h"
//#include "DateTime.h"
#include "KData.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "InstrumentInfo.h"
#include <boost/date_time/posix_time/posix_time.hpp>
#include "DateTimeHelper.h"
///////////////////////////////////////////////////////////////////////
//  CMinute

int MinuteContainer::GetUpperBound() const
{ 
	return size()-1; 
}

void MinuteContainer::sort( )
{
	std::sort(begin(), end());
}

void MinuteContainer::RemoveDirty( )
{
	time_t tmBegin = 0;
	if( size() > 0 )
	{
		time_t tmLatest = back().TradingTime;
		//DateTime	sptime(tmLatest);
		//DateTime	sptimeBegin(sptime.GetYear(),sptime.GetMonth(),sptime.GetDay(),0,0,0);

		tmBegin = boost::posix_time::to_time_t(
			boost::posix_time::ptime(boost::posix_time::from_time_t(tmLatest).date()));
		//tmBegin = sptimeBegin.GetTime();
	}

	
	for (auto rIter = rbegin(); rIter != rend();)
	{
		auto& iMinute = *rIter;
		auto nextIter = std::next(rIter, 1);
		bool bDirty =
			(iMinute.TradingTime <= 0)
			||
			(iMinute.LastPrice < 1e-4)
			||
			(iMinute.Volume < 1e-4)
// 			||
// 			(!DateTime::InTradeTime(iMinute.TradingTime, 60))
			||
			(iMinute.TradingTime < tmBegin)
			||
			(nextIter != rend() && iMinute.TradingTime == nextIter->TradingTime
			&& iMinute.TradingMillisec == nextIter->TradingMillisec)
			;
		rIter = bDirty ? MinuteContainer::reverse_iterator(erase(rIter.base())) : nextIter;
	}
}




bool MinuteContainer::StatVolumeInfo( double *pdVolNow, double *pdVolOuter, double *pdVolInner )
{
	time_t	tmLatest	=	0;
	double	dVolNow = 0, dVolOuter = 0, dVolInner = 0;
	double	dPriceLast	=	-1;
	bool	bRise		=	true;
	for( size_t k=0; k<size(); k++ )
	{
		if( at(k).TradingTime > tmLatest )
		{
			tmLatest	=	(*this)[k].TradingTime;
			dVolNow		=	at(k).Volume;
		}
		double	dPrice	=	at(k).LastPrice;
		if( 0 != k )
		{
			//成交价>=买价，外盘，成交价<=卖价，内盘;
			double	dVolume	=	at(k).Volume - at(k-1).Volume;

			if (at(k).LastPrice >= at(k).BidPrice[0])
			{
				dVolOuter	+=	dVolume;
			}
			else if (at(k).LastPrice <= at(k).AskPrice[0])
			{
				dVolInner	+=	dVolume;
			}
			else
			{
				if( dPrice - dPriceLast > 1e-4 )
					bRise	=	true;
				if( dPrice - dPriceLast < -1e-4 )
					bRise	=	false;
				if( bRise )	dVolOuter	+=	dVolume;
				else		dVolInner	+=	dVolume;
			}
		}
		dPriceLast	=	dPrice;
	}

	if( pdVolNow )
		*pdVolNow = dVolNow;
	if( pdVolOuter )
		*pdVolOuter = dVolOuter;
	if( pdVolInner )
		*pdVolInner = dVolInner;
	return true;
}

bool MinuteContainer::GetDiffPercentMin5( double * pValue )
{
	if( size( ) < 2 )
		return false;
	MINUTE	& minCurrent = at(size()-1);
	for( int i=size()-2; i>=0; i-- )
	{
		time_t	l	=	minCurrent.TradingTime - at(i).TradingTime;
		if( l >= 200 && l <= 600 )
		{
			if( at(i).LastPrice > 1e-4 && minCurrent.LastPrice > 1e-4 )
			{
				if( pValue )	*pValue	=	100*minCurrent.LastPrice / at(i).LastPrice - 100;
				return true;
			}
			break;
		}
	}

	return false;
}

bool MinuteContainer::GetLBDKMinMaxInfo( double dVolAverage, double *pdMin, double *pdMax )
{
	if( dVolAverage < 1e-4 )
		return false;

	double	dMulti	=	1 / dVolAverage;
	double	dMin = 0, dMax = 1;
	for( size_t i=0; i<size(); i++ )
	{
		auto	sptime =boost::posix_time::from_time_t(at(i).TradingTime);
		double	dCurrent = dMulti * at(i).Volume / /*DateTimeHelper::GetTimeTradeRatioOfOneDay( sptime, sptime )*/1;
		if( 0 == i )
		{
			dMin	=	dCurrent;
			dMax	=	dCurrent;
		}
		if( dCurrent < dMin )	dMin	=	dCurrent;
		if( dCurrent > dMax )	dMax	=	dCurrent;
	}

	if( dMax < 1e-4 )
		dMax	=	1;
	if( pdMin )	*pdMin	=	dMin;
	if( pdMax )	*pdMax	=	dMax;
	return true;
}

bool MinuteContainer::GetIndexWave( double *pdWave, size_t nIndex )
{
	double dWave = 0;
	for( std::size_t k=nIndex-12; k<=nIndex; k++ )
	{
		if( k > 0 && k < size() )
			dWave	+=	at(k).LastPrice - at(k-1).LastPrice;
	}
	if( pdWave )
		*pdWave	=	dWave;
	return true;
}


int MinuteContainer::ToKData( KdataContainer & kdata )
{
	kdata.Clear();
	if( size() <= 0 )
		return 0;
	DWORD dwType = at(0).Type*60;
	if(ktypeMin== dwType || ktypeMin5 == dwType || ktypeMin15 == dwType || ktypeMin30 == dwType || ktypeMin60 == dwType )
	{
		//分钟;
		kdata.SetKType(dwType);
		kdata.resize(  size() + 1 );
		for( size_t i=0; i<size(); i++ )
		{
			MINUTE & min = at(i);
			KDATA	kd;
			memset( &kd, 0, sizeof(kd) );
			strcpy( kd.szExchange, min.szExchange);
			strcpy( kd.szCode, min.szCode);
			kd.TradingTime		= min.TradingTime;
			//DateTime sptime(min.TradingTime);
			//kd.TradingDate		= sptime.ToInstrumentTimeMin();

			kd.TradingDate = ToInstrumentTimeDayOrMin(boost::posix_time::from_time_t(min.TradingTime),false);

			kd.OpenPrice		= (min.HighestPrice+min.LowestPrice+min.LastPrice)/3;
			kd.HighestPrice		= min.HighestPrice;
			kd.LowestPrice		= min.LowestPrice;
			kd.ClosePrice		= min.LastPrice;
			kd.Volume	= min.Volume;
			kd.Turnover	= min.Turnover;
			kdata.push_back(kd);
		}
		return kdata.size();
	}
	kdata.resize(  size() / 5 + 5 );
	kdata.SetKType(ktypeMin5);
	int	nCount	=	0;
	KDATA	kd;
	for( size_t pos=0; pos<size(); pos++ )
	{
		MINUTE & min = at( pos );
		nCount	++;
		if( 1 == nCount )
		{
			memset( &kd, 0, sizeof(kd) );
			strcpy( kd.szExchange, min.szExchange);
			strcpy( kd.szCode, min.szCode);
			kd.OpenPrice		= min.LastPrice;
			kd.HighestPrice		= min.HighestPrice;
			kd.LowestPrice		= min.LowestPrice;
			kd.ClosePrice		= min.LastPrice;
			kd.Volume	= min.Volume;
			kd.Turnover	= min.Turnover;
		}
		else
		{
			if( kd.HighestPrice < min.LastPrice )	
				kd.HighestPrice	=	min.HighestPrice;
			if( kd.LowestPrice > min.LastPrice )	
				kd.LowestPrice	=	min.LowestPrice;
			kd.Turnover	+=	min.Turnover;
			kd.Volume	+=	min.Volume;
			kd.ClosePrice		=	min.LastPrice;
		}
		//DateTime sptime(min.TradingTime);
		//DWORD date	= sptime.ToInstrumentTimeMin();

		DWORD date = ToInstrumentTimeDayOrMin(boost::posix_time::from_time_t(min.TradingTime),false);
		if( !(date % 5) )
		{
			kd.TradingTime = min.TradingTime;
			kd.TradingDate = date;
			kdata.push_back(kd);
			nCount = 0;
		}
	}
	return kdata.size();
}


bool MinuteContainer::StatDealInfo( std::vector<DWORD> & adwPrice, std::vector<DWORD> & adwVolume, double * pdMaxVolume )
{
	adwPrice.clear();
	adwVolume.clear();

	for( size_t k=0; k<size(); k++ )
	{
		for (size_t i=0;i<adwPrice.size();i++)
		{
			if (adwPrice[i]==( DWORD(at(k).LastPrice * 1000)))
			{
				adwPrice.erase(adwPrice.begin()+i);
				break;
			}
		}
		adwPrice.push_back( DWORD(at(k).LastPrice * 1000) );
	}
	//adwPrice.Sort( );

	adwVolume.resize( adwPrice.size() );
	for( size_t k=0; k<size(); k++ )
	{
		DWORD	dwPrice		=	DWORD(at(k).LastPrice * 1000);
		DWORD	dwVolume	=	DWORD(at(k).Volume);
		if( k > 0 )
			dwVolume	=	DWORD( at(k).Volume - at(k-1).Volume );

		size_t i;
		for( i=0; i<adwPrice.size(); i++ )
		{
			if( adwPrice[i] == dwPrice )
				break;
		}
		if( i >= adwPrice.size() )
			continue;

		adwVolume[i]	+=	dwVolume;
	}

	double	dMaxVolume = 0;
	for( size_t k=0; k<adwVolume.size(); k++ )
	{
		if( dMaxVolume < (double)adwVolume[k] )
			dMaxVolume	=	(double)adwVolume[k];
	}
	if( pdMaxVolume )
		*pdMaxVolume	=	dMaxVolume;

	return adwPrice.size() > 0;
}
int MinuteContainer::InsertMinuteSort(MINUTE& newElement )
{
	if( newElement.TradingTime <= 0 )
		return -1;
	else if( newElement.LastPrice < 1e-4 )
		return -1;
	else if( newElement.Volume < 1e-4 )
		return -1;
// 	else if( !ctp_time::InTradeTime( newElement.TradingTime, 60 ) )
// 		return -1;

	time_t tmBegin = 0;
	if( size() > 0 )
	{
		time_t tmLatest = back().TradingTime;
// 		DateTime	sptime(tmLatest);
// 		DateTime	sptimeBegin(sptime.GetYear(),sptime.GetMonth(),sptime.GetDay(),0,0,0);
// 		tmBegin = sptimeBegin.GetTime();

		tmBegin = boost::posix_time::to_time_t(boost::posix_time::ptime(boost::posix_time::from_time_t(tmLatest).date()));
	}
	if( newElement.TradingTime <= tmBegin )
		return -1;

	for( int i=size()-1; i>=0; i-- )
	{
		MINUTE	& temp = at(i);
		if( newElement.TradingTime == temp.TradingTime )
		{
			if (temp.HighestPrice>newElement.HighestPrice)
			{
				newElement.HighestPrice=temp.HighestPrice;
			}
			if (temp.LowestPrice<newElement.LowestPrice)
			{
				newElement.LowestPrice=temp.LowestPrice;
			}
			at(i)=newElement;
			return i;
		}
		if( newElement.TradingTime > temp.TradingTime )
		{
			insert(i+1+begin(),newElement);
			return i+1;
		}
	}

	insert(begin(), newElement);
	return 0;
}

bool MinuteContainer::update(const Tick* pReport)
{
	MINUTE lastMinute = {0};
	if (size() > 0)
	{
		lastMinute = back();
	}
	if (!convert_REPORT_to_MINUTE(pReport, &lastMinute))
	{
		return false;
	}
	InsertMinuteSort(lastMinute);
	return true;
}
